﻿using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;

using agree.schema;

using alib;
using alib.Enumerable;
using alib.String;
using alib.Collections;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public abstract class lexent_base : seq_entrymgr_base, ILexicalDerivation, ITfsSlot
	{
		protected lexent_base(IRtParent parent, ILexeme le, Tfs tfs)
			: base(parent, parent, le.EntryMgr)
		{
			this.le = le;
			this.strongref = tfs ?? le.Expanded;
			Debug.Assert(this.strongref != null);
		}

		///////////////////////////////////////////////////////////////////////
		/// <summary>
		/// Lexical entries are only retained by weak reference; but we want those which were expanded during the
		/// main parse phase to hold over to unpacking
		/// </summary>
		protected readonly Tfs strongref;
		protected readonly ILexeme le;
		public String ReadbackTokensForm(ITfsSlot ts) { return le.ReadbackTokensForm(ts); }
		/// 
		///////////////////////////////////////////////////////////////////////

		///////////////////////////////////////////////////////////////////////
		/// 
		public IChartLicense ChartLicense { get { return le; } }
		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		public IReadOnlyList<IDerivation> Daughters { get { return Collection<IDerivation>.None; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public ulong DerivationHash { get { return (ulong)le.Name.GetHashCode() << 16; } }
		public Double Score(MaxEntModel model) { return DerivationFuncs.Score(this, model); }
		public Double ParseSelectionScore { get { return Score(null); } }
		/// 
		///////////////////////////////////////////////////////////////////////


		///////////////////////////////////////////////////////////////////////
		/// 
		public Tfs DerivationTfs() { return strongref; }
		Tfs ITfsSlot.Tfs { get { return strongref; } }
		int ITfsSlot.SlotIndex { get { return 0; } }
		/// 
		///////////////////////////////////////////////////////////////////////


		public Type InstanceType { get { return le.InstanceType; } }
		public int DaughterArity { get { return 0; } }
		public string Name { get { return le.Name; } set { throw alib.not.impl; } }
		Tfs IInstance.Expanded { get { throw not.impl; } }
		Tfs IInstance.Definition { get { throw not.impl; } }

		public override String ToString()
		{
			//return this.TreeDisplay(false, null, null);
			return String.Format("{0} {1:X6}-{2} {3} {4}",
				this.GetType().Name,
				this.Id,
				this.StatusCode,
				this.ChartLicense.Name,
				this.Text().DoubleQuote());
		}

		public StartSymbol[] MatchedStartSymbols { get { return null; } }

		public StartSymbol ItemStartSymbol { get { return null; } }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public abstract class ctl_lex_cspan<W> : lexent_base
		where W : struct, IProximalContext<W>
	{
		protected ctl_lex_cspan(IRtParent parent, ILexeme le, Tfs tfs, W w)
			: base(parent, le, tfs)
		{
			this.w = w;
		}

		///////////////////////////////////////////////////////////////////////
		/// 
		public readonly W w;
		public W ProximalContext { get { return w; } }
		public int CoverageCount { get { return w.CoverageCount; } }
		/// 
		///////////////////////////////////////////////////////////////////////

		public override string ToString()
		{
			return base.ToString() + " " + w.ToString();
		}
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public class ctl_lexref_itok_form : ctl_lex_cspan<ChartSpan>
	{
		public ctl_lexref_itok_form(IRtParent parent, LexicalEntry le, ChartSpan w, String form, Tfs tfs)
			: base(parent, le, tfs, w)
		{
			this.form = form;
		}

		String form;
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract partial class ChartControl<T, W> : ChartResources<W>
		where T : ChartControl<T, W>
		where W : struct, IProximalContext<W>
	{
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{ToString(),nq}")]
		public abstract class _lexent_chartobj : ctl_lex_cspan<W>, agree.IChartObj
		{
			public _lexent_chartobj(IRtParent parent, ILexeme le, Tfs tfs, W w)
				: base(parent, le, tfs, w)
			{
				this.cho = new ChartObjHelper<W>();
				EndTransact(AtomicSeqState.Available);
			}

			///////////////////////////////////////////////////////////////////////
			/// 
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			ChartObjHelper<W> cho;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public IChartObj Next { get { return cho.Next; } }
			public bool TrySetNext(IChartObj a, IChartObj b) { return cho.TrySetNext(a, b); }
			public IChartObj AddToList(IChartObj to_set, ref long next_obj_id) { return cho.AddToList(to_set, ref next_obj_id); }
			/// 
			///////////////////////////////////////////////////////////////////////
		};


		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{ToString(),nq}")]
		public abstract class _chart_atfs_base : ArrayTfs, IChartObj<W>
		{
			public _chart_atfs_base(IUnificationController parent, Rule license, ArrayTfs tfs, IReadOnlyList<IChartObj> rgo, W w, StartSymbol[] ss_matches)
				: base(parent, tfs)
			{
				this.w = w;
				this.cho = new ChartObjHelper<W>();
				this.dvo = new DerivationHelper(license, rgo, ss_matches);
			}

			///////////////////////////////////////////////////////////////////////
			/// 
			public readonly W w;
			public W ProximalContext { [DebuggerStepThrough] get { return w; } }
			public int CoverageCount { [DebuggerStepThrough] get { return w.CoverageCount; } }
			/// 
			///////////////////////////////////////////////////////////////////////


			///////////////////////////////////////////////////////////////////////
			/// 
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			ChartObjHelper<W> cho;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public IChartObj Next { [DebuggerStepThrough] get { return cho.Next; } }
			public bool TrySetNext(IChartObj a, IChartObj b) { return cho.TrySetNext(a, b); }
			public IChartObj AddToList(IChartObj to_set, ref long next_obj_id) { return cho.AddToList(to_set, ref next_obj_id); }
			/// 
			///////////////////////////////////////////////////////////////////////


			///////////////////////////////////////////////////////////////////////
			/// 
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			protected DerivationHelper dvo;
			public IChartLicense ChartLicense { [DebuggerStepThrough] get { return dvo.license; } }
			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			public IReadOnlyList<IDerivation> Daughters { [DebuggerStepThrough] get { return dvo.daughters; } }
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public ulong DerivationHash { [DebuggerStepThrough] get { return dvo.DerivationHash(this); } }
			public Double Score(MaxEntModel model) { return dvo.Score(this, model); }
			public Double ParseSelectionScore { [DebuggerStepThrough] get { return Score(null); } }
			/// 
			///////////////////////////////////////////////////////////////////////


			/// although chart debugger wants to reconstitute the TFS here, this should now be done
			/// by the override, so it is now once again an error to have a restricted TFS arrive here.
			public virtual Tfs DerivationTfs()
			{
				if ((flags & Flags.Restrict) != 0)
					throw new Exception();
				return dvo._revalidate(this) ? this : null;
			}

			///////////////////////////////////////////////////////////////////////
			/// 
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public StartSymbol[] MatchedStartSymbols { get { return dvo.ss_matches; } }

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public StartSymbol ItemStartSymbol { get { return dvo.get_ss(this); } }
			/// 
			///////////////////////////////////////////////////////////////////////

			public override String ToString()
			{
				//return this.TreeDisplay(false, null, null);
				return String.Format("{0} {1:X6}-{2} {3} {4} {5}",
					this.GetType().Name,
					this.Id,
					this.StatusCode,
					this.ChartLicense.Name,
					this.Text().DoubleQuote(),
					this.w);
			}
		};


		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{ToString(),nq}")]
		public abstract class _atfs_unary : _chart_atfs_base
		{
			public _atfs_unary(IUnificationController parent, Rule license, ArrayTfs tfs, IChartObj unary, StartSymbol[] ss_matches)
				: base(parent, license, tfs, new[] { unary }, ((IChartObj<W>)unary).ProximalContext, ss_matches)
			{
			}

			///////////////////////////////////////////////////////////////////////
			/// 
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			protected IChartObj<W> UnaryDaughter { get { return ((IChartObj<W>)dvo.daughters[0]); } }
			/// 
			///////////////////////////////////////////////////////////////////////
		};


		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{ToString(),nq}")]
		public abstract class _atfs_nary : _chart_atfs_base
		{
			public _atfs_nary(IUnificationController parent, Rule license, ArrayTfs tfs, IReadOnlyList<IChartObj> rgo, W w, StartSymbol[] ss_matches)
				: base(parent, license, tfs, rgo, w, ss_matches)
			{
#if DEBUG && false
				this.ae_created_by = ChartControl<T, W>.dbg_active_edge;
				if (ae_created_by != null)
					ctrl.bp("Active edge match", this);
				else
					ctrl.bp("Unary rule match", this);
#endif
			}

#if DEBUG && false
			public ChartControl<T, W>.ActiveEdge ae_created_by = null;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public IChartObj<W> CompletingDaughter
			{
				get
				{
					IDerivation last_dtr;
					if (ae_created_by == null || !ae_created_by.f_rightwards)
						last_dtr = dvo.daughters[0];
					else
						last_dtr = dvo.daughters[dvo.daughters.Count - 1];
					return (IChartObj<W>)last_dtr;
				}
			}
#endif
		};


		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{ToString(),nq}")]
		public abstract class _atfs_unary_pack : _atfs_unary, IPacking
		{
			public _atfs_unary_pack(IUnificationController parent, Rule license, ArrayTfs tfs, IChartObj unary, StartSymbol[] ss_matches)
				: base(parent, license, tfs, unary, ss_matches)
			{
			}

			///////////////////////////////////////////////////////////////////////
			/// 
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			PackingHelper pko;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public List<IPacking> PackedEdges { [DebuggerStepThrough] get { return pko.packed_edges; } }
			public List<IPacking> UsurpPacking() { return Interlocked.Exchange(ref pko.packed_edges, null); }
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public IReadOnlyList<IDerivation> Derivations { [DebuggerStepThrough] get { return pko.Derivations(this); } }
			public void HoistPackingFrom(IPacking pe_old) { pko.HoistPackingFrom(pe_old); }
			/// 
			///////////////////////////////////////////////////////////////////////


			///////////////////////////////////////////////////////////////////////
			/// 
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			Tfs dtfs;
			public override Tfs DerivationTfs()
			{
				var _tmp = dtfs;
				if (_tmp == null)
				{
					if ((_tmp = DerivationFuncs.reconstitute_tfs(this, fsu)) == null || !dvo._revalidate(_tmp))
						_tmp = td.NullTfs;
					this.dtfs = _tmp;
				}
				return _tmp is NullTfs ? null : _tmp;
			}
			/// 
			///////////////////////////////////////////////////////////////////////
		};


		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{ToString(),nq}")]
		public abstract class _atfs_nary_pack : _atfs_nary, IPacking
		{
			public _atfs_nary_pack(IUnificationController parent, Rule rule, ArrayTfs tfs, IReadOnlyList<IChartObj> rgo, W w, StartSymbol[] ss_matches)
				: base(parent, rule, tfs, rgo, w, ss_matches)
			{
			}

			///////////////////////////////////////////////////////////////////////
			/// 
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			PackingHelper pko;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public List<IPacking> PackedEdges { [DebuggerStepThrough] get { return pko.packed_edges; } }
			public List<IPacking> UsurpPacking() { return Interlocked.Exchange(ref pko.packed_edges, null); }
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public IReadOnlyList<IDerivation> Derivations { [DebuggerStepThrough] get { return pko.Derivations(this); } }
			public void HoistPackingFrom(IPacking pe_old) { pko.HoistPackingFrom(pe_old); }
			/// 
			///////////////////////////////////////////////////////////////////////


			///////////////////////////////////////////////////////////////////////
			/// 
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			Tfs dtfs;
			public override Tfs DerivationTfs()
			{
				var _tmp = dtfs;
				if (_tmp == null)
				{
					if ((_tmp = DerivationFuncs.reconstitute_tfs(this, fsu)) == null || !dvo._revalidate(_tmp))
						_tmp = td.NullTfs;
					this.dtfs = _tmp;
				}
				return _tmp is NullTfs ? null : _tmp;
			}
			/// 
			///////////////////////////////////////////////////////////////////////
		};
	};
}
